----------------------
-- Player Class
----------------------
Player = {}
Player.__index = Player

function Player.new()
    local p = {}
    setmetatable(p, Player)
    
    -- consts
    p.c_max_gravity = 4.0
    p.c_gravity = 0.2
    p.c_start_stop_speed_limit = 1.5
    p.c_dash_speed_factor = 3.5
    p.c_dash_time_limit = 0.25
    p.c_dash_delay_limit = 0.15
    p.c_jump_hold_time = 0.25
    
    -- stats
    p.hp = 99
    p.max_hp = 99
    p.hearts = 3
    p.max_hearts = 3
    
    -- variables for physics -> naa pois
	p.x = 0.0
	p.y = 0.0
	p.vel_x = 0.0
	p.vel_y = 0.0
    p.accel_x = 0.5
    p.accel_y = 0.0
    
    -- variables and -- init
    p.duck = false
    p.jump = false
    p.jump_count = 0
    p.on_ground = true
    p.jump_time = 0.0
    p.double_jump_time = 0.0
    p.attack = false
    p.jump_attack = false
    p.attack_id = 1
    p.attack_delay = 0.0 -- delay for different hit
    p.dash = false
    p.dash_time = 0.0
    p.dash_delay = 0.25
    p.air_dash = false
    p.wall_jump = false
    p.wall = false
    p.wall_jump_time = 0.0
    p.wall_side = 0
    p.ceil = false
    p.allow_drop_down_on_platform = false
    p.sleep_time = 0.0
    p.delay_for_next_attack = 0.0 -- delay when you can hit you next hit
    
    -- for tempotary key 
    p.temp_dir_key = "undefined"
    
    -- bounding boxses
    p.bounding_box = Rectangle.new(0, 0, 20, 30)
    p.weapon_hit_box = Rectangle.new(0, 0, 30, 20)
    p.weapon_hit_box_active = false
    --p.weapon_hit_enemy = false
    
    -- create sprite
    p.sprite = Sprite.new()
    --p.sprite.accel_x = 0.5
    
    -- images and animations
    p.sprite:loadImage("idle", "content/hero/idle.png")
    p.sprite:loadImage("run", "content/hero/running.png")
    p.sprite:loadImage("startstop", "content/hero/startstop.png")
    p.sprite:loadImage("duck", "content/hero/duck.png")
    p.sprite:loadImage("jump", "content/hero/jumping.png")
    p.sprite:loadImage("doublejump", "content/hero/doublejump.png")
    p.sprite:loadImage("attack1", "content/hero/attack1.png")
    p.sprite:loadImage("attack2", "content/hero/attack2.png")
    p.sprite:loadImage("attack3", "content/hero/attack3.png")
    p.sprite:loadImage("jumpattack", "content/hero/jumpattack.png")
    
    p.sprite:addAnimation("idle", "idle", 64, 64, {0}, 1, false)
    p.sprite:addAnimation("run", "run", 64, 64, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0.06, true)
    p.sprite:addAnimation("startstop", "startstop", 64, 64, {0}, 0.1, false)
    p.sprite:addAnimation("duck", "duck", 64, 64, {0, 1, 2, 3, 4}, 0.04, false)
    p.sprite:addAnimation("stand", "duck", 64, 64, {5, 6}, 0.04, false)
    p.sprite:addAnimation("jump-up", "jump", 64, 64, {0, 1, 2}, 0.1, false)
    p.sprite:addAnimation("jump-down", "jump", 64, 64, {3, 4}, 0.1, false)
    p.sprite:addAnimation("doublejump", "doublejump", 64, 64, {0, 1, 2, 3, 4, 5, 6, 7}, 0.04, true)
    p.sprite:addAnimation("attack1", "attack1", 64, 64, {0, 1, 2, 3, 4, 5, 6}, 0.04, false)
    p.sprite:addAnimation("attack2", "attack2", 64, 64, {0, 1, 2, 3, 4, 5, 6}, 0.04, false)
    p.sprite:addAnimation("attack3", "attack3", 64, 64, {0, 1, 2, 3, 4, 5, 6}, 0.04, false)
    p.sprite:addAnimation("jumpattack", "jumpattack", 64, 64, {0, 1, 2, 3, 4, 5, 6, 7}, 0.04, false)
    
    -- swords
    p.weapon = Sprite.new()
    p.weapon.visible = false
    p.weapon:setOrigin(16, 16) -- offset
    p.weapon:loadImage("sword-attack1", "content/hero/sword-attack1.png")
    p.weapon:loadImage("sword-attack2", "content/hero/sword-attack2.png")
    p.weapon:loadImage("sword-attack3", "content/hero/sword-attack3.png")
    p.weapon:loadImage("sword-jumpattack", "content/hero/sword-jumpattack.png")
    p.weapon:addAnimation("sword-attack1", "sword-attack1", 96, 96, {0, 1, 2, 3, 4, 5, 6}, 0.04, false)
    p.weapon:addAnimation("sword-attack2", "sword-attack2", 96, 96, {0, 1, 2, 3, 4, 5, 6}, 0.04, false)
    p.weapon:addAnimation("sword-attack3", "sword-attack3", 96, 96, {0, 1, 2, 3, 4, 5, 6}, 0.04, false)
    p.weapon:addAnimation("sword-jumpattack", "sword-jumpattack", 96, 96, {0, 1, 2, 3, 4, 5, 6, 7}, 0.04, false)
    
    -- shield
    p.shield = Sprite.new()
    p.shield:loadImage("shield", "content/hero/wooden-shield.png")
    p.shield:addAnimation("shield", "shield", 64, 64, {0, 1, 2, 3, 4}, 0.04, false)
    p.shield.visible = false    
    p.shield_hit = false
    p.shield_hit_time = 0.0

    -- player take hit
    p.hit_control_lock = false
    p.invincible = false
    p.invincibility_time = 0.0
    
    -- interact with world objects
    p.interact = false
    
    -- particle systems
    p.ps_feather = nil
    p.ps_dust = nil
    p:initFeatherParticleSystem()
    p:initDustParticleSystem()
    
    return p
end

----------------------
-- init feather particle system
----------------------
function Player:initFeatherParticleSystem()
    local sp = Sprite.new()
    sp:loadImage("sp", "content/particles/feather.png")

	self.ps_feather = love.graphics.newParticleSystem(sp:getCurrentImage(), 10)
	self.ps_feather:setLifetime(0.75)
	self.ps_feather:setParticleLife(0.75)
   	self.ps_feather:setEmissionRate(100)
   	self.ps_feather:setDirection(math.rad(90))
   	self.ps_feather:setGravity(-100, -150)
   	self.ps_feather:setSpeed(25, 50)
   	self.ps_feather:setSpread(math.rad(120))
   	self.ps_feather:setSpin(math.rad(-180), math.rad(180), 1)
	--self.ps_feather:setRotation(-math.pi, math.pi)
	--self.ps_feather:setTangentialAcceleration(50, 100)
	self.ps_feather:setColor(255, 255, 255, 255, 255, 255, 255, 0)
end

----------------------
-- init dust particle system
----------------------
function Player:initDustParticleSystem()
	self.ps_dust = love.graphics.newParticleSystem(love.graphics.newImage("content/particles/dust.png"), 10)
	self.ps_dust:setLifetime(-1) -- infinity
	self.ps_dust:setParticleLife(0.5)
   	self.ps_dust:setEmissionRate(3)
   	self.ps_dust:setDirection(math.rad(270))
   	self.ps_dust:setSpeed(15, 25)
   	self.ps_dust:setSpread(math.rad(180))
	self.ps_dust:setSize(0.75, 0.1, 1)
    --self.ps_dust:setColor(255, 255, 255, 255, 255, 255, 255, 123)
end

----------------------
-- reset all actions
----------------------
function Player:resetActions()
    self.jump = false
    self.wall_jump = false
    self.jump_attack = false
    self.attack = false
    self.duck = false
    self.wall = false
    self.dash = false
    self.air_dash = false
end

----------------------
-- Update animations
----------------------
function Player:updateAnimations()
    if self.on_ground then
        -- dashing
        if self.dash then
            self.sprite:playAnimation("startstop")
            
        -- attacking
        elseif self.attack then
            self.sprite:playAnimation("attack" .. self.attack_id)
            
            -- remove attacking status when animation is complete
            if self.sprite.animation_complete then
                self.attack = false
            end
        -- ducking
        elseif self.duck then
            self.sprite:playAnimation("duck")
            
            -- and draw shield if enabled
            if self.shield.visible then
                self.shield.playAnimation("shield")
            end
        else
            -- movement
            if self.vel_x == 0.0 then
                if self.sprite:isCurrentAnimation("duck") then
                    self.sprite:playAnimation("stand")
                else
                    if self.sprite:isCurrentAnimation("stand") then
                        if self.sprite.animation_complete then
                            self.sprite:playAnimation("idle")
                        end
                    else
                        self.sprite:playAnimation("idle")
                    end
                end
            elseif (math.abs(self.vel_x) > 0.5 and 
            	    math.abs(self.vel_x) <= self.c_start_stop_speed_limit) then
            	   
                self.sprite:playAnimation("startstop")
            elseif math.abs(self.vel_x) > self.c_start_stop_speed_limit then
                self.sprite:playAnimation("run")
            end
        end
    else
        -- jump attack
        if self.jump_attack then
            self.sprite:playAnimation("jumpattack")
            
            -- remove jump attack status when animation is complete
            if self.sprite.animation_complete then
                self.jump_attack = false
            end
        else
            -- jumping, CHANGE jump_count == 2 ja uncommentoi = vanhat setit
            if self.air_dash then
                self.sprite:playAnimation("startstop")
            else
                if self.vel_y < 0.0 then
                    if self.jump_count >= 2 then
                        self.sprite:playAnimation("doublejump")
                    else
                        self.sprite:playAnimation("jump-up")
                    end
                else
                    if self.sprite:isCurrentAnimation("doublejump") then
                        if self.sprite.animation_complete then
                           -- self.sprite:playAnimation("jump-down")
                        end
                    else --if self.jump_count <= 1 then
                        if self.jump_count <= 1 then
                            self.sprite:playAnimation("jump-down")
                        else
                            self.sprite:playAnimation("doublejump")
                        end
                        --print(self.jump_count)
                    end
                end
            end
        end
    end
    
    --print(self.sprite.current_animation)
end

----------------------
-- Update weapon and attack delay
----------------------
function Player:updateWeapon()
    -- update attack delay
    self.attack_delay = self.attack_delay + global_delta_time

    -- in the beginning always visible
    self.weapon.visible = false
    
    -- jump attack
    if self.jump_attack then
        self.weapon.visible = true
        
        if self.weapon:isCurrentAnimation("sword-jumpattack") then
            if self.weapon.animation_complete then
                self.weapon:replayAnimation("sword-jumpattack")
            end
        else
            self.weapon:playAnimation("sword-jumpattack")
        end
    -- ground attacks
    elseif self.attack then
        self.weapon.visible = true
        
        if self.weapon:isCurrentAnimation("sword-attack" .. self.attack_id) then
            if self.weapon.animation_complete then
                self.weapon:replayAnimation("sword-attack" .. self.attack_id)
            end
        else
            self.weapon:playAnimation("sword-attack" .. self.attack_id)
        end
    end

    --self.weapon:setPosition(self.sprite.x, self.sprite.y)
    self.weapon:flip(self.sprite.flip_x, false)
    
    -- update sprite
    self.weapon:update()
end

----------------------
-- When player hit on the ground, set state for variables
----------------------
function Player:setGroundState()
    self.on_ground = true
    if self.vel_y >= 0.0 then
    	self.jump_count = 0
    end
    self.jump_time = 0.0
    self.jump_attack = false
    self.air_dash = false
    self.wall_jump = false
    self.wall_jump_time = 0.0
    self.double_jump_time = 0.0
    self.vel_y = 0.0 -- uusin
    
    if self.hit_control_lock then
        self.hit_control_lock = false
        self.vel_x = 0.0
        self.vel_y = 0.0
    end
end

----------------------
-- When player hits his head on the ceil
----------------------
function Player:setCeilState()
	self.vel_y = 0.0 -- uusin
    self.jump_time = 10.0
    self.jump = false
    self.ceil = true
    
    -- Ei esteta tuplahypyn syntya
    -- vaikka paa osuu kattoon.
    if self.jump_count >= 2 then
        self.double_jump_time = 10.0
    end
end

----------------------
-- Sets wall states
----------------------
function Player:setWallState()
	self.vel_x = 0.0 -- uusin
    self.wall = true
    self.air_dash = false
    self.dash_time = 0.0
    self.dash = false
    if self.wall_jump_time > 0.25 then
        self.wall_jump = false
    end
    self.wall_jump_time = 0.0
end

----------------------
-- Is shield enabled
----------------------
function Player:isShieldOn()
    return (self.shield.visible and shield_acquired)
end

----------------------
-- Update attack delay
----------------------
function Player:updateAttackDelay()
	if self.delay_for_next_attack > 0.0 then
		self.delay_for_next_attack = self.delay_for_next_attack - global_delta_time
	end
end

----------------------
-- Update shield
----------------------
function Player:updateShield()
    if self.shield.visible then
        self.shield:update()
        self.shield.flip_x = self.sprite.flip_x
    end
end

----------------------
-- Update player
----------------------
function Player:update()
	-- sleep for a while when hit
	if self.sleep_time > 0.0 then
		self.sleep_time = self.sleep_time - global_delta_time
		return
	end

    -- if flickering do not update side, this is for hit flickering.
    if not self.hit_control_lock then
        self:updateSide()
    end
    
    self:updateGravity()
    self:updateDash()
    self:updateWallJump()
    self:updateTakenHit()
    self:updateShieldHit()
    self:updateAnimations()
    self:updateMove()
    
    -- update sprite/animations
    self.sprite:update()
    
    -- update bounding box and hit box
    self:updateBoundingBox()
    self:updateHitBox()
    
    -- update Weapon and shield
    self:updateWeapon()
    self:updateAttackDelay()
    self:updateShield()
    
    -- update particles
    self.ps_feather:update(global_delta_time)
    self.ps_dust:update(global_delta_time)
    
    -- dust particle logic
    if not self.on_ground or (self.vel_x == 0.0 and self.vel_y == 0.0) or self.dash then
    	self.ps_dust:stop()
    else
    	if not self.ps_dust:isActive() then
    		self.ps_dust:start()
    	end
    end
end

----------------------
-- reset velocity
----------------------
function Player:resetVelocity()
    self.sprite.vel_x = 0.0
    self.sprite.vel_y = 0.0
end

----------------------
-- update move
----------------------
function Player:updateMove()
    local x_limit = 2.0
    local y_limit = self.c_max_gravity
    if self.dash or self.air_dash then y_limit = 0.0 x_limit = 5.0 end
    --if self.air_dash then x_limit = 3.0 end
    
    self.vel_x = clamp(self.vel_x, -x_limit, x_limit)
    self.vel_y = clamp(self.vel_y, -self.c_max_gravity, y_limit)
    
    self.x = self.vel_x + self.x
    self.y = self.vel_y + self.y
    
    -- fixes the corner bug
    if self.vel_x < 0 then
        self.x = math.floor(self.x)
    else
        self.x = math.ceil(self.x)
    end
    
    if self.vel_y < 0 then
        self.y = math.floor(self.y)
    else
        self.y = math.ceil(self.y)
    end

    -- if attacking we have to slow it down so that player does
    -- not slide during the attack.
    if self.attack then
        self:updateFriction()
    end
end

----------------------
-- update friction
----------------------
function Player:updateFriction()
--     if self.vel_x < 0 then
--         self.vel_x = self.vel_x + (self.accel_x * 0.25)
--     elseif self.vel_x > 0 then
--         self.vel_x = self.vel_x - (self.accel_x * 0.25)
--     end
    
    -- do not update friction if shield hit is taken
    if self.shield_hit then return end
    
    self.vel_x = self.vel_x * 0.7
    self.vel_x = tendToZero(self.vel_x, 0.1)
end

----------------------
-- Reset states
----------------------
function Player:resetStates()
	self.wall = false
	self.on_ground = false
end

----------------------
-- update gravity
----------------------
function Player:updateGravity()
    if not self.jump and not self.on_ground then
    	--if isBetween(self.vel_y, 0.0, 2.0) then self.vel_y = 2.0 end
		self.vel_y = self.vel_y + self.c_gravity
    end
end

----------------------
-- update dash
----------------------
function Player:updateDash()
    if self.dash or self.air_dash then
        self.dash_time = self.dash_time + global_delta_time
        if self.dash_time <= self.c_dash_time_limit then
            local dir = 1
            if self.vel_x == 0 then
                if self.sprite.flip_x then dir = -1 end
            else
                if self.vel_x < 0.0 then dir = -1 end
            end
            self.vel_x = self.vel_x + (dir * (self.accel_x * self.c_dash_speed_factor))
        else
            self.air_dash = false
            self.dash = false
            self.dash_time = 0.0
            self.dash_delay = 0.0
        end
    else
        self.dash_delay = self.dash_delay + global_delta_time
        self.dash_delay = clamp(self.dash_delay, 0.0, 1.0)
    end
end

----------------------
-- can player take hit?
----------------------
function Player:canTakeHit()
    return (not self.invincible and self.sleep_time <= 0.0)
end

----------------------
-- can player hit enemy?
----------------------
function Player:canHit()
    return self.weapon_hit_box_active
end

----------------------
-- take hit
----------------------
function Player:hit()
    --self.weapon_hit_enemy = true
    --self.weapon_hit_box_active = false
    self.sleep_time = 0.1
end

----------------------
-- take hit
----------------------
function Player:takeHit(damage)
    -- reset actions
    self:resetActions()

    self.sprite:stopFlickering()
    self.sprite:playFlickering(1.0, 0.2)
    
    -- send it away
    if self.sprite.flip_x then
        self.vel_x = 2.0
        self.vel_y = -2.0
    else
        self.vel_x = -2.0
        self.vel_y = -2.0
    end
    
    -- not ground anymore 
    self.on_ground = false
    
    -- reset invincibility and control lock
    self.hit_control_lock = true
    self.invincible = true
    self.invincibility_time = 0.0
    
    -- take away some health
    self.hp = self.hp - damage
    self.hp = clamp(self.hp, 0, 100)
    if self.hp <= 0 then
        self.hearts = self.hearts - 1
        if self.hearts < 0 then
            return true
        else
            self.hp = self.max_hp
        end
    end
    
    return false
end

----------------------
-- When hit enemy with shield
----------------------
function Player:takeShieldHit(side)
    -- send it away
    if side == 0 then
        self.vel_x = 2.0
    else
        self.vel_x = -2.0
    end
    
    -- hit states
    self.shield_hit = true
    self.shield_hit_time = 0.1
end

----------------------
-- Update shield hit
----------------------
function Player:updateShieldHit()
    -- update shield hit if true
    if self.shield_hit then
        if self.shield_hit_time >= 0.0 then
            self.shield_hit_time = self.shield_hit_time - global_delta_time
        else
            self.shield_hit = false
            self.vel_x = 0.0
        end
    end
end

----------------------
-- update hit
----------------------
function Player:updateTakenHit()
    if self.hit_control_lock then 
        if self.on_ground then
            self:updateFriction()            
        end
    end
    
    -- update invincibility
    if self.invincible then
        self.invincibility_time = self.invincibility_time + global_delta_time
        if self.invincibility_time >= 1.0 then
            self.invincible = false
        end
    end
end

----------------------
-- update walljump
----------------------
function Player:updateWallJump()
    if self.wall_jump then
        self.wall_jump_time = self.wall_jump_time + global_delta_time
        if self.wall_jump_time >= 0.5 then
            self.wall_jump = false
            self.wall_jump_time = 0.0
        end
    end
end

----------------------
-- update side
----------------------
function Player:updateSide()
    -- do not update side if shield hit
    if self.shield_hit then return end

    -- if vel x < 0, moving left
    if self.vel_x < 0 then
        if self.jump_count >= 2 and not self.air_dash then
            -- cannot change if doublejump is active
            if self.sprite:isCurrentAnimation("doublejump") then
                if self.sprite.animation_complete then
                    self.sprite:flip(true, false)
                end
            end
        else
            self.sprite:flip(true, false)
        end
    -- if moving right
    elseif self.vel_x > 0 then
        if self.jump_count >= 2 and not self.air_dash then
            -- cannot change if doublejump is active
            if self.sprite:isCurrentAnimation("doublejump") then
                if self.sprite.animation_complete then
                    self.sprite:flip(false, false)
                end
            end
        else
            self.sprite:flip(false, false)
        end
    end
end

----------------------
-- Update bounding box
----------------------
function Player:updateBoundingBox()
	self.bounding_box.x = self.x
	self.bounding_box.y = self.y
	self.bounding_box.height = 30
end

----------------------
-- Update weapon hit box
----------------------
function Player:updateHitBox()
    if self.sprite:isCurrentAnimation("attack" .. self.attack_id) or 
       self.sprite:isCurrentAnimation("jumpattack") then
       
        -- frames between 2-4 if is on gorund, air 1-4
        local min_f = 2
        local max_f = 4
        if isBetween(self.sprite.current_frame_index, min_f, max_f) then
            -- side affects the position
            if not self.sprite.flip_x then
                self.weapon_hit_box.x = self.x + 27
            else
                self.weapon_hit_box.x = self.x - 37
            end
            
            self.weapon_hit_box.y = self.y + 8
            self.weapon_hit_box_active = true
        else
            self.weapon_hit_box_active = false
            --self.weapon_hit_enemy = false
        end
    else
        self.weapon_hit_box_active = false
        --self.weapon_hit_enemy = false
    end
    
    -- Checks wether player has already hitted enemy
    -- if it is, then no need hit box to be active
    -- weapon_hit_enemy inactivated again after active frames.
    -- if self.weapon_hit_enemy then self.weapon_hit_box_active = false end
end

----------------------
-- Updates Player actions when
-- key press event occured.
-- ex. pressing jump or attack
----------------------
function Player:updateKeyPress(key)
    if self.hit_control_lock then return end
    
    -- jump countter
    if key == "down" then
        -- jump only when you are ground
        if self.on_ground then self.jump = true self.on_ground = false end
        
        -- disable duck and shield
        if self.duck then
            self.duck = false
            self.shield.visible = false
        end
    
    	if double_jump_acquired then
	        self.jump_count = self.jump_count + 1
        end
        
        if self.dash then
            -- self.air_dash = true
            self.dash = false
            self.dash_time = 0.0
            -- fixes bug if dash is 
            -- canceled in the middle with jump
            self.vel_x = 0.0
        end
        
        -- if attacked before jump, cancel attack
        self.attack = false
        --self.weapon.visible = false
        
		-- feather particles
        if self.jump_count == 2 then
        	local b = self.bounding_box
			self.ps_feather:setPosition(b:left() + b.width * 0.5, b:bottom())
            if not self.ps_feather:isActive() then
                self.ps_feather:start()
            else
                self.ps_feather:reset()
            end
        end
    end
    
    -- attacking, only ground and not during dash, and attack delay is 0.0
    if sword_acquired and not self.interact then
		if key == "left" and self.on_ground and not self.dash and self.delay_for_next_attack <= 0.0 then
			-- update hit box again, when new hit is done
			-- self.weapon_hit_enemy = false
			self.attack = true
			self.delay_for_next_attack = 0.2
			
			-- disable duck
			if self.duck then
				self.duck = false
			end
			
			-- next id
			if self.attack_delay <= 0.4 then
				self.attack_id = self.attack_id + 1 -- math.random(1, 3)
				if self.attack_id > 3 then self.attack_id = 1 end
			else
				self.attack_id = 1
			end
			
			-- delay = 0.0
			self.attack_delay = 0.0
            self.vel_x = 0.0 -- added 17.10.2010
		end
    
		-- attackin in the air
		if key == "left" and not self.on_ground then
			self.jump_attack = true
			self.weapon.visible = true
		end
    end
    
    -- dash skill
    if dash_acquired then
		if key =="right" and self.dash_delay >= self.c_dash_delay_limit and 
           not self.dash and not self.air_dash then
            if self.on_ground then
                self.dash = true
            else
                self.air_dash = true                
            end
            
			self.attack = false
		end
    end
end

----------------------
-- Updates Player actions when
-- key down left or right
----------------------
function Player:leftAndRight()
    -- reset temp key
    -- self.temp_dir_key = "undefined"
    
    -- if not either one, then slow down and
    if not love.keyboard.isDown("a") and not love.keyboard.isDown("d") then
        if not self.wall_jump and not self.air_dash then
            self:updateFriction()
        end
        
        -- reset direction and return
        self.temp_dir_key = "undefined"
        return
    end

    -- moving left
    if love.keyboard.isDown("a") and not love.keyboard.isDown("d") then
    	-- so you can change direction while attacking
    	if self.attack or self.jump_attack then
    		self.sprite:flip(true, false)
    	end
    	
        if not self.attack and not self.wall_jump and not self.dash and not self.air_dash then
            if self.vel_x > 0 then self.vel_x = 0 end
            self.vel_x = self.vel_x - self.accel_x
            
            -- if facing the wall and your on the wall, velocity = 0.0
            if self.wall and self.sprite.flip_x and self.temp_dir_key == "a" then
                self.vel_x = 0.0
            end
        end
        self.temp_dir_key = "a"
    end
    
    -- moving right
    if love.keyboard.isDown("d") and not love.keyboard.isDown("a") then
		-- so you can change direction while attacking
    	if self.attack or self.jump_attack then
			self.sprite:flip(false, false)
    	end
    
        if not self.attack and not self.wall_jump and not self.dash and not self.air_dash then
            if self.vel_x < 0 then self.vel_x = 0 end
            self.vel_x = self.vel_x + self.accel_x
            
            -- if facing the wall and your on the wall, velocity = 0.0
            if self.wall and not self.sprite.flip_x and self.temp_dir_key == "d" then 
                self.vel_x = 0.0
            end
        end
        self.temp_dir_key = "d"
    end
    
    local b = self.bounding_box
    local s = b:left()
    if self.vel_x < 0.0 then s = b:right() end
    -- b:left() + b.width * 0.5
	self.ps_dust:setPosition(s, b:bottom() - 5)
	self.ps_dust:start()
end

----------------------
-- Updates Player actions when
-- key down event occured.
----------------------
function Player:updateKeyDown()
    if self.hit_control_lock then return end
    
    -- remove this later
    if love.keyboard.isDown("w") then
        self.y = 0
        self.vel_y = 0
        --print("jep")
    end
    
    -- drop down on platform
    if love.keyboard.isDown("s") and love.keyboard.isDown("down") then
    	self.allow_drop_down_on_platform = true
    	self.jump = false
    	self.duck = false
    else
    	self.allow_drop_down_on_platform = false
    end

    -- jumping cannot jump if taken hit
    if love.keyboard.isDown("down") then
        -- normal jump
        -- print(self.jump_time .. " " .. self.double_jump_time)
        if self.jump then
            self.jump_time = self.jump_time + global_delta_time
            if self.jump_time < self.c_jump_hold_time then
                self.vel_y = -((1.0 - self.jump_time / 0.5) * 5.0)
            else
                --if self.vel_y < 0 then self.vel_y = 0 end
                self.jump = false
            end
        end
        
        -- double jump
        if self.jump_count == 2 then
            self.double_jump_time = self.double_jump_time + global_delta_time
            if self.double_jump_time < self.c_jump_hold_time then
                self.vel_y = -((1.0 - self.double_jump_time / 0.5) * 3.5)
            else
                --if self.vel_y < 0 then self.vel_y = 0 end
            end
        end
        
        -- moved from keyPressed
        -- wall jump
        if wall_jump_acquired and not self.wall_jump then
			if self.wall and self.jump_count > 2 and not self.wall_jump then
					if self.sprite.flip_x and self.temp_dir_key == "a" then
						self.vel_x = 2.0
						self.vel_y = -5.0
						self.sprite:flip(false, false)
					elseif not self.sprite.flip_x and self.temp_dir_key == "d" then
						self.vel_x = -2.0
						self.vel_y = -5.0
						self.sprite:flip(true, false)
					end
				
				self.wall_jump = true
				self.jump_count = self.jump_count + 1 -- add
			end
        end
    
        -- you can move freely in the air
        -- left or right
        self:leftAndRight()

    -- ducking
    elseif love.keyboard.isDown("s") and self.on_ground and not self.dash then
        self.duck = true
        
        -- enable shield and reset animation
        if not self.shield.visible and shield_acquired then
            self.shield.visible = true
            self.shield:resetAnimation()
        end
        
        -- disable duck and shield
        if self.attack then 
            self.duck = false
            self.shield.visible = false
        end
        
        self:updateFriction()
    else    
        -- false duck and jump, and jump_time = 0.0
        self.duck = false
        self.jump = false
        self.jump_time = 0.0
        self.shield.visible = false
        
        -- jump velocity reset
        if self.vel_y < 0 then self.vel_y = 0 end
    
        -- left or right
        self:leftAndRight()
    end
end

----------------------
-- Draw Player and the weapon
----------------------
function Player:draw(camera)
	-- remove this
    --local box = self.bounding_box
    --love.graphics.rectangle("fill", camera:getRenderX(box.x - 10), camera:getRenderY(box.y), box.width + 20, box.height)
    
    -- weapon offsets
    local xp = self.x - 22
    local yp = self.y - 33
    if self.duck then yp = self.y - 33 end
    
    if self.sprite:isCurrentAnimation("run") then
    	yp = yp - 1
    end
    
    -- new offset
    -- yp = yp + 4
    
    if camera ~= nil then
        xp = camera:getRenderX(xp)
        yp = camera:getRenderY(yp) 
    end
    
    -- dust particles
--     love.graphics.draw(self.ps_dust, -camera.x, -camera.y)
    
    -- draw sprite and weapon
    self.sprite:draw(xp, yp)
    self.weapon:draw(xp, yp)
    
    -- do not draw if hit taken
    if not self.hit_control_lock then
        self.shield:draw(xp, yp)
    end
    
    -- remove this
    --[[
    if self.weapon_hit_box_active then
        local wep = self.weapon_hit_box
        love.graphics.rectangle("fill", camera:getRenderX(wep.x), camera:getRenderY(wep.y), wep.width, wep.height)
    end
    --]]
end

-- effects
function Player:drawEffects(camera)
    -- draw particles
    love.graphics.draw(self.ps_feather, -camera.x, -camera.y)
    love.graphics.draw(self.ps_dust, -camera.x, -camera.y)
    --love.graphics.setColorMode("modulate")
    --love.graphics.setBlendMode("alpha")
end
